#ifndef _XDG_TCP_SERVER_HPP_
#define _XDG_TCP_SERVER_HPP_ 

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>
#include <map>
#include <thread>
#include <atomic>
#include <mutex>
#include <algorithm>
#include <sys/ioctl.h>
#include "xdgSocketIO.hpp"
#include "xdgEpoll.hpp"
#include "../concurrentqueue/blockingconcurrentqueue.h"

namespace xdg { 


class sendProxy {
public:
    // 获取单例实例
    static sendProxy& instance() {
        static sendProxy instance;
        return instance;
    }


    bool init(){
        if (m_thread) return true;

        m_thread = std::make_unique<std::thread>([this]() {
            while (!m_stop.load())
            {
                bool got = false;
                std::pair<int,std::shared_ptr<std::vector<char>>> data(0, nullptr);
                try {
                    // wait_dequeue_timed 返回 true 表示成功出队，false 表示超时（未出队）
                    got = m_sendQueue.wait_dequeue_timed(data, 10000);
                } catch (...) {
                    // 有些实现可能抛异常（极少见），记录并继续或退出
                    std::cerr << "[ThreadPool] Warning: exception from wait_dequeue_timed\n";
                    got = false;
                }

                if (!got) {
                    // 超时或出错：循环回到开头检查停止条件
                    continue;
                }

                // 成功取出任务：执行任务（在执行前无需再修改队列计数）
                try {
                    if (data.second) {
                        SocketIO::sendSocket(data.first, data.second->data(), data.second->size());
                    }
                } catch (const std::exception &e) {
                    std::cerr << "[ThreadPool] Exception in task: " << e.what() << std::endl;
                } catch (...) {
                    std::cerr << "[ThreadPool] Unknown exception in task" << std::endl;
                }

            }
        });

        return m_thread != nullptr;
    }

    int send(int fd, const char* buf, size_t len, int max_retries = 100) {
        int retry_count = 0;
        int errorcode = 0;
        
        while (retry_count < max_retries) {
            try {
                // 尝试入队
                m_sendQueue.enqueue(std::make_pair(fd, 
                    std::make_shared<std::vector<char>>(buf, buf + len)));
                return errorcode;
                
            } catch (const std::bad_alloc& e) {
                errorcode = -1;
            } catch (const std::exception& e) {
                errorcode = -2;
            } catch (...) {
                errorcode = -3;
            }

            // 重试计数增加
            retry_count++;

            // 指数退避策略：等待时间逐渐增加
            int wait_ms = std::min(1000, 10 * (1 << std::min(retry_count, 6))); // 最大等待1秒
            std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
        }

        return errorcode;
    }

    void destroy() {
        m_stop.store(true);
        if (m_thread && m_thread->joinable()) {
            m_thread->join();
            m_thread.reset(); // 释放管理的线程对象，将其设置为 nullptr
        }
    }

    bool isRunning() const {
        return m_thread != nullptr && !m_stop.load();
    }

    // 禁止拷贝和赋值
    sendProxy(const sendProxy&) = delete;
    sendProxy& operator=(const sendProxy&) = delete;

private:
    sendProxy() = default;
    ~sendProxy() { destroy(); }

    moodycamel::BlockingConcurrentQueue<std::pair<int, std::shared_ptr<std::vector<char>>>> m_sendQueue;
    std::unique_ptr<std::thread> m_thread;
    std::atomic<bool> m_stop{false};
};


class TcpServer; // 前向声明

/**
 * @brief TCP连接上下文，封装了单个客户端连接的所有信息和操作。
 * @details 每个客户端连接都对应一个 TcpContext 实例，包含了该连接的文件描述符、
 *          对端地址信息、连接状态、接收缓冲区等。通过 shared_ptr 进行生命周期管理。
 */
class TcpContext
{
public:
    /**
     * @brief 构造函数
     * @param fd 客户端 socket 文件描述符
     * @param peer_ip 客户端 IP 地址（字符串形式）
     * @param peer_port 客户端端口号
     * @param server 指向拥有此上下文的服务器实例的指针，用于回调服务器的断开处理方法。
     */
    TcpContext(int fd, const std::string& peer_ip, unsigned short peer_port, std::function<void(int)> onRequestDisconnect) 
        : m_fd(fd), 
          m_ip(peer_ip), 
          m_port(peer_port), 
          m_ConnectedStatus(true),
          m_onRequestDisconnect(std::move(onRequestDisconnect))
    {
        // 初始化时连接状态为 true，接收缓冲区为空。预分配 4KB 空间，减少后续的内存重新分配次数，提升性能
        m_recv_buffer.reserve(4096);
    }

    /**
     * @brief 析构函数，自动关闭套接字资源。
     * @details 当 TcpContext 对象被销毁时（通常是 shared_ptr 引用计数归零时），
     *          自动关闭对应的 socket 文件描述符，释放系统资源。
     */
    ~TcpContext() {
        // 不在析构函数中调用 disconnect()，以避免在析构期使用 shared_from_this 或触发复杂回调链。只做防御性关闭：如果 fd 仍然有效就关闭它。
        if (m_fd >= 0) {
            SocketIO::closeSocket(m_fd);
            m_fd = -1;
        }
    }

    // 禁止拷贝构造和拷贝赋值。因为 TcpContext 拥有独占资源（文件描述符），不应该被拷贝
    TcpContext(const TcpContext&) = delete;
    TcpContext& operator=(const TcpContext&) = delete;

    /**
     * @brief 获取 Socket 文件描述符
     * @return int 文件描述符的值
     */
    int getFd() const { return m_fd; }

    /**
     * @brief 获取客户端 IP 地址
     * @return std::string 客户端 IP 地址（字符串形式）
     */
    std::string clientIp() const { return m_ip; }

    /**
     * @brief 获取客户端端口号
     * @return unsigned short 客户端端口号
     */
    unsigned short clientPort() const { return m_port; }

    /**
     * @brief 获取当前连接状态
     * @return true 表示连接中, false 表示已断开
     */
    bool isConnected() const { return m_ConnectedStatus; }

    /**
     * @brief 主动从外部断开此连接。
     * @details 这个方法允许用户代码主动关闭某个客户端连接。
     *          它会触发服务器的完整断开清理流程，包括从 epoll 移除、
     *          调用断开回调、关闭 socket 等。
     *          此方法是线程安全的，因为内部调用的 handleClientDisconnect 有锁保护。
     *          
     *          注意：使用 m_ConnectedStatus 标志防止重复调用。
     */
    void disconnect() {
        // 防止重复调用
        if (!m_ConnectedStatus) { return; }

        m_ConnectedStatus = false; // 立即标记为已断开，防止重入

        // 不在这里 修改 / close(fd)。统一让 handleClientDisconnect / 析构处理关闭工作。
        if (m_onRequestDisconnect) {
            m_onRequestDisconnect(m_fd); // 将 fd 值传入，server 会统一移除 epoll、调用回调并最终关闭 fd
        }
    }

    /**
     * @brief 向客户端发送数据(内部会拷贝一份数据)
     * @param buf 发送缓冲区指针
     * @param len 要发送的字节数
     * @return 成功返回 0，失败返回 -1（内存不足）、-2（其他错误）、-3（未知错误）
     */
    int send(const char *buf, size_t len) {
        if (!m_ConnectedStatus) return -1;
        // 发送数据
        return sendProxy::instance().send(m_fd, buf, len);
    }

private:
    /**
     * @brief 获取内部接收缓冲区的可变引用。
     * @return std::vector<char>& 接收缓冲区的引用
     * @details 接收缓冲区用于在拆包模式（非RAW模式）下暂存尚未构成完整包的数据。
     *          返回引用允许服务器直接操作缓冲区，避免不必要的拷贝。
     *          使用 vector<char> 而非 string 的原因：
     *          1. 语义更清晰（二进制数据 vs 文本数据）
     *          2. 避免 string 的某些文本优化开销（如 SSO、null 终止符等）
     *          3. 更符合网络缓冲区的语义
     */
    std::vector<char>& getRecvBuffer() {
        return m_recv_buffer;
    }

    /**
     * @brief 向内部接收缓冲区追加数据。
     * @param data 要追加的数据指针
     * @param len 数据长度（字节数）
     * @details 此方法用于在接收到数据后，将数据追加到上下文的私有缓冲区中，
     *          以便后续的拆包逻辑进行处理。
     *          使用 insert + end() 迭代器的方式追加，效率高于逐字节 push_back。
     */
    void appendData(const char* data, size_t len) {
        m_recv_buffer.insert(m_recv_buffer.end(), data, data + len);
    }

    /**
     * @brief 获取当前接收缓冲区的大小（已缓存的字节数）
     * @return size_t 缓冲区大小
     * @details 用于检查缓冲区是否超限，或判断是否有足够数据进行拆包。
     */
    size_t getRecvBufferSize() const {
        return m_recv_buffer.size();
    }

private:
    int m_fd;                          // 客户端 socket 文件描述符
    std::string m_ip;                  // 客户端 IP 地址
    unsigned short m_port;             // 客户端端口号
    bool m_ConnectedStatus;            // 连接状态标志：true 表示连接中，false 表示已断开
    std::vector<char> m_recv_buffer;   // 每个连接独有的接收缓冲区，用于拆包（改用 vector<char>）
    std::function<void(int)>  m_onRequestDisconnect;  // 回调：请求服务器断开（传入 fd）

     friend class TcpServer; // 允许 TcpServer 访问内部成员
};


/**
 * @brief 定义 TCP 数据包的拆包规则
 * @details TCP 是流式协议，需要应用层定义消息边界。拆包规则决定了如何从 TCP 字节流中识别和提取完整的应用层消息。
 */
enum class UnpackingRule
{
    /**
     * @brief 无拆包规则，接收到数据就立即触发回调。不检查 m_pack_length
     * @details 每次 recv 返回数据就直接回调，不做任何缓冲和拆包处理。
     *          适用于短连接、或者应用层自己处理粘包拆包的场景。
     */
    RAW,

    /**
     * @brief 按固定长度拆包。
     * @details 每个消息的长度是固定的。服务器会缓冲数据，直到积累了指定长度的字节后，才触发一次回调。
     *          需要通过 setUnpackingRule 额外指定消息长度。
     */
    FIXED_LENGTH,

    /**
     * @brief 按行拆包（以 "\r\n" 作为消息边界）。接收时+解析时双重检查 m_pack_length
     * @details 每条消息以 "\r\n" 结尾。服务器会缓冲数据，直到找到完整的一行，才触发回调。适用于文本协议，如 HTTP、SMTP 等。
     */
    LINE_BASED,

    /**
     * @brief 按 "4字节头部(消息体长度) + 消息体" 格式拆包。接收时检查头部 m_pack_length（推荐）
     * @details 消息格式：[4字节长度(网络字节序)] + [消息体]
     *          头部的4字节表示紧随其后的消息体的长度。
     *          这是最常用和推荐的拆包方式，能高效处理任意长度的消息。
     */
    HEADER_BODY
};


// ============ 回调函数类型定义 ============

/**
 * @brief 客户端连接回调函数类型
 * @param ctx 新连接的客户端上下文（shared_ptr）
 * @return int 返回值：0 表示接受连接，非0 表示拒绝连接
 * @details 当有新客户端连接成功后，会调用此回调。
 *          用户可以在此回调中进行连接验证、日志记录等操作。
 *          如果返回非0值，服务器会拒绝该连接并关闭对应的 socket。
 */
using CallbackConnection = std::function<int(std::shared_ptr<TcpContext>)>;

/**
 * @brief 客户端断开连接回调函数类型
 * @param ctx 断开连接的客户端上下文（shared_ptr）
 * @details 当客户端断开连接时（包括主动断开、被动断开、错误断开），
 *          会调用此回调。用户可以在此进行清理工作、日志记录等。
 */
using CallbackClose = std::function<void(std::shared_ptr<TcpContext>)>;

/**
 * @brief 数据到达回调函数类型
 * @param ctx 接收到数据的客户端上下文（shared_ptr）
 * @param buf 数据缓冲区指针
 * @param len 数据长度（字节数）
 * @details 当接收到完整的应用层消息时（根据拆包规则），会调用此回调。
 *          用户在此回调中处理业务逻辑。
 *          注意：buf 指向的数据在回调返回后可能失效，如需保存请立即拷贝。
 */
using CallbackMessage = std::function<void(std::shared_ptr<TcpContext>, const char*, size_t)>;

/**
 * @brief 数据到达回调函数类型（带共享指针版本）
 * @param ctx 接收到数据的客户端上下文（shared_ptr）
 * @param pack 数据包的共享指针，包含完整的数据内容
 * @details 当接收到完整的应用层消息时（根据拆包规则），会调用此回调。
 *          用户在此回调中处理业务逻辑，数据包以共享指针形式传递，生命周期自动管理。
 */
using CallbackMessageShared = std::function<void(std::shared_ptr<TcpContext>, std::shared_ptr<std::vector<char>>)>;

/**
 * @brief 错误回调函数类型
 * @param errMsg 错误信息字符串
 * @details 当服务器内部发生错误时，会调用此回调，传递错误信息。
 *          用户可以在此进行日志记录或错误处理。
 */
using CallbackError = std::function<void(const std::string&)>;


/**
 * @brief 一个基于 Epoll 的事件驱动 TCP 服务器框架。
 * @details 这是一个高性能、易用的 TCP 服务器实现。主要特性包括：
 *          - 基于 epoll 实现高效的 I/O 多路复用
 *          - 非阻塞 I/O + ET（边缘触发）模式
 *          - 支持多种拆包规则，自动处理 TCP 粘包/拆包问题
 *          - 线程安全，事件循环运行在独立线程中
 *          - 基于回调的编程模型，易于使用
 *          - RAII 风格，自动管理资源生命周期
 */
class TcpServer
{
/******************************** 构造/析构函数 ********************************/
public:
    /**
     * @brief 构造函数。
     * @param ip 要监听的服务器 IP 地址。可以是 IPv4 或 IPv6 地址。
     *           使用 "0.0.0.0" 监听所有 IPv4 地址，"::" 监听所有 IPv6 地址。
     * @param port 要监听的服务器端口号。范围：1-65535。
     * @details 构造时仅初始化成员变量，不进行实际的网络操作。
     *          需要调用 start() 方法才会开始监听和接受连接。
     */
    TcpServer(const std::string& ip, int port);

    /**
     * @brief 析构函数，会自动调用 stop() 停止服务器。
     * @details 确保服务器安全退出，关闭所有连接，释放所有资源。
     *          采用 RAII 原则，对象销毁时自动清理。
     */
    ~TcpServer();

    // 禁止拷贝、赋值、移动操作
    // 服务器对象持有独占资源（监听 socket、线程、epoll 实例等），不应该被拷贝或移动
    TcpServer(const TcpServer&) = delete;
    TcpServer& operator=(const TcpServer&) = delete;
    TcpServer(TcpServer&&) = delete;
    TcpServer& operator=(TcpServer&&) = delete;

/******************************** 公共接口函数 ********************************/
public:
    /**
     * @brief 启动服务器。
     * @return int 成功返回 0, 失败返回 -1。
     * @details 此方法会执行以下步骤：
     *          1. 创建监听 socket
     *          2. 设置 socket 选项（地址重用、非阻塞）
     *          3. 绑定地址和端口
     *          4. 开始监听
     *          5. 将监听 socket 加入 epoll
     *          6. 在独立线程中启动事件循环
     *          此方法是非阻塞的，调用后立即返回，事件循环在后台线程中运行。
     *          如果服务器已经在运行，重复调用会失败并返回 -1。
     */
    int start();

    /**
     * @brief 停止服务器。
     * @return int 总是返回 0。
     * @details 此方法会执行以下步骤：
     *          1. 设置停止标志，通知事件循环线程退出
     *          2. 等待事件循环线程安全退出（join）
     *          3. 关闭监听 socket
     *          4. 关闭所有客户端连接
     *          5. 清理所有资源
     *          此方法会阻塞，直到所有清理工作完成。
     *          多次调用是安全的，如果服务器未运行则直接返回。
     */
    int stop();

    /**
     * @brief 设置服务器的拆包规则。
     * @param rule 拆包规则枚举值，决定如何从 TCP 字节流中识别完整消息。
     * @param pack_length 数据包长度限制（含义因规则而异）：
     *        - RAW: 忽略此参数，无长度限制
     *        - FIXED_LENGTH: 固定包长度（必须 > 0），每个包必须是这个长度
     *        - LINE_BASED: 单行最大长度（0 表示无限制）。超过此长度的行会导致断开连接
     *        - HEADER_BODY: 消息体最大长度（0 表示无限制）。超过此长度的消息会导致断开连接
     * @details 必须在调用 start() 之前设置。
     *          默认规则是 RAW（无拆包），即接收到数据就立即回调。
     *          如果设置为 FIXED_LENGTH，必须同时指定 pack_length 参数且不能为 0。
     */
    void setUnpackingRule(UnpackingRule rule, size_t pack_length = 0);

    /**
     * @brief 设置数据包长度限制（在已设置拆包规则后修改）
     * @param pack_length 新的长度限制（字节数）
     * @details 对各模式的作用：
     *          - RAW: 无效果，忽略
     *          - FIXED_LENGTH: 修改固定包长度
     *          - LINE_BASED: 修改单行最大长度（0 表示无限制）
     *          - HEADER_BODY: 修改消息体最大长度（0 表示无限制）
     *          
     *          此方法允许在服务器运行时动态调整长度限制。
     */
    void setPackLength(size_t pack_length) { m_pack_length = pack_length; }

    /**
     * @brief 获取当前的数据包长度限制
     * @return size_t 当前设置的长度限制（字节数）
     */
    size_t getPackLength() const { return m_pack_length; }

    /**
     * @brief 设置最大客户端连接数限制
     * @param max_connections 最大连接数限制
     */
    void setMaxConnections(size_t max_connections) { m_max_client_count = max_connections; }

    /**
     * @brief 获取当前设置的最大客户端连接数限制
     */
    size_t getMaxConnections() const { return m_max_client_count; }

    /**
     * @brief 设置新客户端连接时的回调函数。
     * @param callback 用户定义的连接回调函数。
     *                 如果传入 nullptr，则恢复为默认回调（总是接受连接）。
     * @details 回调函数签名：int callback(std::shared_ptr<TcpContext> ctx)
     *          返回 0 表示接受连接，返回非 0 表示拒绝连接。
     *          在此回调中可以进行：连接验证、日志记录、初始化连接状态等。
     */
    void setClientConnectCallback(CallbackConnection callback);

    /**
     * @brief 设置客户端断开连接时的回调函数。
     * @param callback 用户定义的断开连接回调函数。
     *                 如果传入 nullptr，则恢复为默认回调（什么都不做）。
     * @details 回调函数签名：void callback(std::shared_ptr<TcpContext> ctx)
     *          在此回调中可以进行：资源清理、日志记录、统计信息更新等。
     *          注意：此回调返回后，TcpContext 对象可能被销毁（如果没有其他持有者）。
     */
    void setClientDisconnectCallback(CallbackClose callback);

    /**
     * @brief 设置接收到客户端数据时的回调函数。（原始指针版本）
     * @param callback 用户定义的数据到达回调函数。
     *                 如果传入 nullptr，则恢复为默认回调（什么都不做）。
     * @details 回调函数签名：void callback(std::shared_ptr<TcpContext> ctx, const char* buf, size_t len)
     *          在此回调中处理业务逻辑，如解析协议、处理请求、生成响应等。
     *          注意：buf 指向的数据在回调返回后可能失效，如需保存请立即拷贝。
     */
    void setDataArrivedCallback(CallbackMessage callback);

    /**
     * @brief 设置接收到客户端数据时的回调函数（共享指针版本）。
     * @param callback 用户定义的数据到达回调函数。
     *                 如果传入 nullptr，则恢复为默认回调（什么都不做）。
     * @details 回调函数签名：void callback(std::shared_ptr<TcpContext> ctx, std::shared_ptr<std::vector<char>> pack)
     *          在此回调中处理业务逻辑，数据包以共享指针形式传递，生命周期自动管理。
     *          注意：如果同时设置了两种数据回调，共享指针版本优先。
     */
    void setDataArrivedCallbackShared(CallbackMessageShared callback);

    /**
     * @brief 设置服务器内部发生错误时的回调函数。
     * @param callback 用户定义的错误回调函数。
     *                 如果传入 nullptr，则恢复为默认回调（什么都不做）。
     * @details 回调函数签名：void callback(const std::string& errMsg)
     *          在此回调中可以进行：日志记录、告警通知等。
     *          注意：不应该在此回调中执行耗时操作，以免阻塞事件循环。
     */
    void setErrorCallback(CallbackError callback);

/******************************** 内部成员函数 ********************************/
private:
    /**
     * @brief 事件循环主函数，由后台线程执行。
     * @details 这是服务器的核心，负责：
     *          1. 调用 epoll_wait 等待 I/O 事件
     *          2. 遍历就绪的事件
     *          3. 根据事件类型分发到相应的处理函数
     *          4. 循环往复，直到收到停止信号
     *          此函数在独立线程中运行，不会阻塞主线程。
     */
    void eventLoop();

    /**
     * @brief 处理监听 socket 上的新连接请求。
     * @details 每次调用只处理一个 accept。如果还有等待的连接，由于监听 fd 使用 LT 模式，
     *          下次 epoll_wait 会再次返回 EPOLLIN 事件，从而在 eventLoop 中再次调用此函数。
     *          这样保持了事件循环的清晰性：一个事件触发一次处理函数。
     * 
     *          处理流程：
     *          1. 调用 accept 接受一个新连接（非阻塞）
     *          2. 如果 accept 返回 EAGAIN，说明当前没有等待的连接，直接返回
     *          3. 获取客户端地址信息（IP 和端口）
     *          4. 创建 TcpContext 对象
     *          5. 调用用户的连接回调，如果返回非 0 则拒绝连接
     *          6. 将新连接设为非阻塞，并加入 epoll（使用 ET 模式）
     *          7. 将新连接加入客户端管理 map
     */
    void handleNewConnection();

    /**
     * @brief 处理指定客户端的数据到达事件。
     * @param fd 发生事件的客户端文件描述符。
     * @details 处理流程因拆包规则而异：
     * 
     *          【RAW 模式】：
     *          - 使用 ioctl(FIONREAD) 查询内核缓冲区中可读字节数
     *          - 动态分配合适大小的缓冲区（最大限制 64KB，防止恶意攻击）
     *          - 循环调用 recv 读取数据，直到返回 EAGAIN
     *          - 每次读取到数据就立即调用用户回调。不使用应用层缓冲区
     * 
     *          【其他模式（FIXED_LENGTH / LINE_BASED / HEADER_BODY）】：
     *          - 循环调用 recv 读取数据到临时缓冲区（8KB），直到返回 EAGAIN
     *          - 将读取到的数据追加到 TcpContext 的私有接收缓冲区
     *          - 【关键】在追加后立即检查缓冲区大小是否超过 m_pack_length 限制
     *            如果超限且该模式需要限制（LINE_BASED/HEADER_BODY），则断开连接
     *          - 根据拆包规则，循环从缓冲区中提取完整的消息：
     *            · FIXED_LENGTH: 积累够固定长度后提取
     *            · LINE_BASED: 查找 "\r\n" 后提取，如果单行超长则断开
     *            · HEADER_BODY: 先读取 4 字节头部获取长度，检查长度是否超限，再提取完整包
     *          - 对每个完整的消息调用用户回调
     * 
     *          特殊情况处理：
     *          - 如果 recv 返回 0，表示对端关闭，调用 handleClientDisconnect
     *          - 如果 recv 返回 -1 且 errno 不是 EAGAIN/EWOULDBLOCK，表示出错，调用 handleClientDisconnect
     */
    void handleClientData(int fd);

    /**
     * @brief 处理指定客户端的断开连接事件。这是清理客户端资源的唯一统一入口。
     * @param fd 断开连接的客户端文件描述符。
     * @details 此函数负责完整的断开清理流程：
     *          1. 加锁并从客户端管理 map 中移除该连接
     *             - 如果 fd 不在 map 中，说明已经被清理过，直接返回（防止重复处理）
     *             - 获取 TcpContext 的 shared_ptr 并保存在局部变量中
     *          2. 从 epoll 监听中移除该 fd
     *          3. 调用用户的断开连接回调
     *          4. 当函数返回时，局部变量 context 被销毁
     *             - 如果这是最后一个指向该 TcpContext 的 shared_ptr
     *             - 则 TcpContext 对象被析构，自动关闭 socket fd
     * 
     *          此函数被以下场景调用：
     *          - eventLoop 检测到 EPOLLHUP / EPOLLERR / EPOLLRDHUP
     *          - handleClientData 中 recv 返回 0 或出错
     *          - handleClientData 中检测到缓冲区超限
     *          - TcpContext::disconnect() 主动断开
     * 
     *          线程安全性：使用互斥锁保护 m_clientMap 的访问和修改。
     */
    void handleClientDisconnect(int fd);

    /**
     * @brief 默认的客户端连接回调函数。
     * @param ctx 客户端连接上下文。
     * @return int 总是返回 0，表示接受连接。
     * @details 如果用户未设置连接回调，则使用此默认实现。
     */
    static int defaultClientConnectCallback(std::shared_ptr<TcpContext> ctx) { (void)ctx; return 0; }

    /**
     * @brief 默认的客户端断开连接回调函数。
     * @param ctx 客户端连接上下文。
     * @details 如果用户未设置断开回调，则使用此默认实现（什么都不做）。
     */
    static void defaultClientDisconnectCallback(std::shared_ptr<TcpContext> ctx) { (void)ctx; }

    /**
     * @brief 默认的数据到达回调函数。
     * @param ctx 客户端连接上下文。
     * @param buf 数据缓冲区。
     * @param len 数据长度。
     * @details 如果用户未设置数据回调，则使用此默认实现（什么都不做）。
     */
    static void defaultDataArrivedCallback(std::shared_ptr<TcpContext> ctx, const char* buf, size_t len) { (void)ctx; (void)buf; (void)len;}

    /**
     * @brief 默认的共享指针数据到达回调函数。
     * @param ctx 客户端连接上下文。
     * @param pack 数据包的共享指针。
     * @details 如果用户未设置共享指针数据回调，则使用此默认实现（什么都不做）。
     */
    static void defaultDataArrivedCallbackShared(std::shared_ptr<TcpContext> ctx, std::shared_ptr<std::vector<char>> pack) { (void)ctx; (void)pack; }

    /**
     * @brief 默认的错误回调函数。
     * @param errMsg 错误信息。
     * @details 如果用户未设置错误回调，则使用此默认实现（什么都不做）。
     */
    static void defaultErrorCallback(const std::string& errMsg) { (void)errMsg; }

/******************************** 私有成员变量 ********************************/
private:
    std::string m_ip;                                      // 服务器监听的 IP 地址
    unsigned short m_port;                                 // 服务器监听的端口号
    int m_listen_fd;                                       // 监听 socket 的文件描述符

    std::unique_ptr<Epoll> m_epollptr;                    // epoll 实例的智能指针
    std::map<int, std::shared_ptr<TcpContext>> m_clientMap; // 管理所有客户端连接的 map，key 是 fd，value 是 TcpContext
    
    std::thread m_event_loop_thread;                       // 事件循环运行的线程
    std::atomic<bool> m_is_running;                        // 原子变量，标识服务器是否正在运行
    mutable std::mutex m_client_mutex;                     // 保护 m_clientMap 的互斥锁，确保线程安全
    
    UnpackingRule m_unpacking_rule;                        // 当前使用的拆包规则
    size_t m_pack_length;                                  // 数据包长度限制（含义因规则而异）
                                                           // RAW: 不受此限制
                                                           // FIXED_LENGTH: 固定长度，每个包必须是这个长度
                                                           // LINE_BASED: 单行最大长度（超过则断开连接，0表示无限制）
                                                           // HEADER_BODY: 消息体最大长度（超过则断开连接，0表示无限制）


    size_t m_max_client_count;                             // 最大连接数限制
    size_t m_current_client_count;                         // 当前连接数
    CallbackConnection m_clientConnectCallback;            // 客户端连接回调函数
    CallbackClose m_clientDisconnectCallback;              // 客户端断开连接回调函数
    CallbackMessage m_dataArrivedCallback;                 // 数据到达回调函数（原始指针版本）
    CallbackMessageShared m_dataArrivedCallbackShared;     // 数据到达回调函数（共享指针版本）
    CallbackError m_errorCallback;                         // 错误回调函数
};

// ================================================================================
// =================== 以下是所有成员函数的 inline 实现 ===========================
// ================================================================================

/**
 * @brief TcpContext 的 disconnect 实现。
 * @details 通过调用服务器的 handleClientDisconnect 来统一处理断开逻辑，
 *          确保线程安全和资源清理的一致性。
 *          这是用户代码主动断开连接的唯一正确方式。
 */

/**
 * @brief 构造函数实现。
 * @details 初始化所有成员变量，并设置默认的回调函数。
 */
inline TcpServer::TcpServer(const std::string& ip, int port) 
    : m_ip(ip), 
      m_port(port), 
      m_listen_fd(-1),                              // 初始时监听 fd 无效
      m_epollptr(std::make_unique<Epoll>(1024)),    // 创建 epoll 实例，初始容量 1024
      m_is_running(false),                          // 初始时服务器未运行
      m_unpacking_rule(UnpackingRule::RAW),         // 默认使用 RAW 规则（无拆包）
      m_pack_length(8192),                          // 默认长度限制为 8KB
      m_max_client_count(10000),                    // 默认最大连接数为 10000
      m_current_client_count(0)                     // 当前连接数为 0
{
    // 设置所有回调函数为默认的空实现，防止用户未设置时调用空指针导致崩溃
    m_clientConnectCallback = defaultClientConnectCallback;
    m_clientDisconnectCallback = defaultClientDisconnectCallback;
    m_dataArrivedCallback = defaultDataArrivedCallback;
    m_dataArrivedCallbackShared = nullptr;  // 共享指针回调默认为空
    m_errorCallback = defaultErrorCallback;
}

/**
 * @brief 析构函数实现。
 * @details 确保在对象销毁时，服务器已完全停止并清理了所有资源。
 */
inline TcpServer::~TcpServer()
{
    // 在析构时确保服务器已停止，这是 RAII 原则的体现
    stop();
}

/**
 * @brief 启动服务器的实现。
 * @return int 成功返回 0，失败返回 -1。
 */
inline int TcpServer::start()
{
    // 防止重复启动：如果服务器已经在运行，报错并返回
    if (m_is_running) {
        if (m_errorCallback) {
            m_errorCallback("warning: start -> Server is already running.");
        }
        return -1;
    }

    // 步骤 1: 创建监听 socket
    // 根据 IP 地址格式判断是 IPv4 还是 IPv6
    int address_family = (m_ip.find(':') != std::string::npos) ? AF_INET6 : AF_INET;
    m_listen_fd = SocketIO::createTcpSocket(address_family);
    if (m_listen_fd < 0) {
        if (m_errorCallback) {
            m_errorCallback("error: start -> Failed to create listen socket.");
        }
        return -1;
    }

    // 步骤 2: 设置 socket 选项
    // 设置地址重用，允许服务器快速重启（避免 TIME_WAIT 状态导致的地址被占用）
    SocketIO::setReuseAddr(m_listen_fd, true);
    // 【关键】将监听 socket 设为非阻塞模式，以配合事件驱动模型
    SocketIO::setNonBlocking(m_listen_fd);

    // 步骤 3: 绑定地址和端口
    if (SocketIO::bindSocket(m_listen_fd, m_ip, m_port) < 0) {
        if (m_errorCallback) {
            m_errorCallback("error: start -> Failed to bind socket.");
        }
        SocketIO::closeSocket(m_listen_fd);
        m_listen_fd = -1;
        return -1;
    }
    
    // 步骤 4: 开始监听
    if (SocketIO::listenSocket(m_listen_fd) < 0) {
        if (m_errorCallback) {
            m_errorCallback("error: start -> Failed to listen on socket.");
        }
        SocketIO::closeSocket(m_listen_fd);
        m_listen_fd = -1;
        return -1;
    }

    // 步骤 5: 创建sendProxy 实例
    if (!sendProxy::instance().init()) {
        if (m_errorCallback) {
            m_errorCallback("error: start -> Failed to init sendProxy.");
        }
        SocketIO::closeSocket(m_listen_fd);
        m_listen_fd = -1;
        return -1; 
    }

    // 步骤 6: 将监听 socket 加入 epoll
    // 只关心连接请求（EPOLLIN 事件），监听 fd 使用默认的 LT 模式，更简单健壮
    if (m_epollptr->addSocket(m_listen_fd, EPOLLIN) < 0) {
        if (m_errorCallback) {
            m_errorCallback("error: start -> Failed to add listen socket to epoll.");
        }
        SocketIO::closeSocket(m_listen_fd);
        m_listen_fd = -1;
        return -1;
    }

    // 步骤 7: 设置运行状态并启动事件循环线程
    m_is_running = true;
    m_event_loop_thread = std::thread(&TcpServer::eventLoop, this);
    
    return 0;
}

/**
 * @brief 停止服务器的实现。
 * @return int 总是返回 0。
 */
inline int TcpServer::stop()
{
    // 如果服务器未运行，直接返回
    if (!m_is_running) { return 0; }

    // 步骤 1: 设置运行标志为 false，向事件循环线程发送停止信号
    m_is_running = false;

    // 2) 快照所有当前 client 的 fd（避免在遍历时 map 被修改）
    std::vector<int> fds;
    {
        std::lock_guard<std::mutex> lock(m_client_mutex);
        fds.reserve(m_clientMap.size());
        for (const auto &p : m_clientMap) fds.push_back(p.first);
    }

    // 3) 强制断开所有 client（注意：handleClientDisconnect 线程安全）
    for (int fd : fds) {
        handleClientDisconnect(fd);
    }

    // 4) 等待事件循环线程退出（epoll_wait 可能仍在阻塞，最多等待 500ms）
    if (m_event_loop_thread.joinable()) { m_event_loop_thread.join(); }

    // 5) 清理 listen fd
    if (m_listen_fd >= 0) {
        m_epollptr->deleteSocket(m_listen_fd);
        SocketIO::closeSocket(m_listen_fd);
        m_listen_fd = -1;
    }

    // 6) 防御性地再次清理 map（如果有残留）
    {
        std::lock_guard<std::mutex> lock(m_client_mutex);
        for (auto& pair : m_clientMap) {
            m_epollptr->deleteSocket(pair.first);
            // TcpContext 的析构会关闭 socket
        }
        m_clientMap.clear();
        m_current_client_count = 0;
    }

    return 0;
}

/**
 * @brief 设置拆包规则的实现。
 */
inline void TcpServer::setUnpackingRule(UnpackingRule rule, size_t pack_length)
{
    m_unpacking_rule = rule;
    m_pack_length = pack_length;
}

/**
 * @brief 设置连接回调的实现。
 */
inline void TcpServer::setClientConnectCallback(CallbackConnection callback) {
    // 如果传入 nullptr，则恢复为默认回调，保证安全（不会调用空指针）
    m_clientConnectCallback = callback ? callback : defaultClientConnectCallback;
}

/**
 * @brief 设置断开回调的实现。
 */
inline void TcpServer::setClientDisconnectCallback(CallbackClose callback) {
    m_clientDisconnectCallback = callback ? callback : defaultClientDisconnectCallback;
}

/**
 * @brief 设置消息回调的实现。
 */
inline void TcpServer::setDataArrivedCallback(CallbackMessage callback) {
    m_dataArrivedCallback = callback ? callback : defaultDataArrivedCallback;
}

/**
 * @brief 设置共享指针消息回调的实现。
 */
inline void TcpServer::setDataArrivedCallbackShared(CallbackMessageShared callback) {
    m_dataArrivedCallbackShared = callback ? callback : defaultDataArrivedCallbackShared;
}

/**
 * @brief 设置错误回调的实现。
 */
inline void TcpServer::setErrorCallback(CallbackError callback) {
    m_errorCallback = callback ? callback : defaultErrorCallback;
}

/**
 * @brief 事件循环的实现。
 * @details 这是服务器的心脏，在独立线程中持续运行，负责所有 I/O 事件的处理。
 */
inline void TcpServer::eventLoop()
{
    // 只要服务器处于运行状态就持续循环
    while (m_is_running) {
        // 等待 epoll 事件，超时时间为 500 毫秒
        // 超时返回 0，允许循环定期检查 m_is_running 标志
        int num_events = m_epollptr->wait(500);

        // 情况 1: 超时，没有事件发生，继续下一轮循环
        if (num_events == 0) { continue; }

        // 情况 2: epoll_wait 出错
        if (num_events < 0) {
            // 如果是被信号中断（EINTR），这是正常情况，继续循环
            if (errno == EINTR) { continue; }

            // 其他 epoll 致命错误则终止循环
            if(m_errorCallback) { m_errorCallback("error: eventLoop -> epoll_wait failed."); }

            break; // 跳出循环，线程退出
        }

        // 情况 3: 有事件发生，遍历所有就绪的事件
        for (int i = 0; i < num_events; ++i) {
            int fd = m_epollptr->getEventFd(i);         // 获取就绪事件的文件描述符
            uint32_t events = m_epollptr->getEvents(i); // 获取就绪事件的类型（EPOLLIN/EPOLLHUP/EPOLLERR等）

            // ========== 事件分发：判断是监听 socket 还是客户端 socket ==========
            if (fd == m_listen_fd) {
                // 有新的客户端连接请求到达
                handleNewConnection();

            } else {
                // 客户端 socket 的事件

                // 采用两个独立的 if 来处理事件，而不是 if-else
                // 原因：客户端在关闭前可能还发送了数据，如果用 if-else，
                //       当同时有 EPOLLIN 和 EPOLLHUP 事件时，只会处理其中一个，导致数据丢失。
                
                // 优先处理读事件（EPOLLIN），以读取客户端在关闭前发送的最后数据
                if (events & EPOLLIN) {
                    handleClientData(fd);
                }

                // 在处理完读事件后，再检查是否有错误或挂起事件
                // 注意：handleClientData 内部可能已经因为 recv 返回 0 或超限而处理了断开
                // 所以这里需要检查客户端是否还存在于 map 中，防止重复处理
                if (events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP)) {
                    bool exists = false;
                    {
                        std::lock_guard<std::mutex> lock(m_client_mutex);
                        exists = (m_clientMap.count(fd) != 0);
                    }
                    if (exists) { handleClientDisconnect(fd); } // 在不持锁的情况下调用，内部会自己加锁移除

                } // 错误或挂起事件处理结束
            } // 客户端 socket 事件处理结束
        } // for 循环遍历 epoll 事件结束
    } // while 循环结束
}

/**
 * @brief 新连接处理的实现。
 * @details 每次调用只处理一个 accept。
 *          如果还有等待的连接，epoll_wait 会在下次调用时再次返回 EPOLLIN 事件。
 */
inline void TcpServer::handleNewConnection()
{
    if (m_current_client_count >= m_max_client_count) {
        m_errorCallback("error: handleNewConnection -> max client count reached.");
        return;
    }

    // 准备存储客户端地址信息的结构体
    sockaddr_storage client_addr;
    
    // 调用 accept 接受一个新连接
    // 因为监听 fd 已设为非阻塞，所以这里的 accept 不会阻塞
    int client_fd = SocketIO::acceptSocket(m_listen_fd, &client_addr);
    
    // accept 返回 < 0 表示出错或没有连接
    if (client_fd < 0) {
        // 如果错误是 EAGAIN 或 EWOULDBLOCK，表示当前没有等待的连接
        // 这是正常情况，直接返回
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            return;
        } else {
            // 其他 accept 错误，记录错误信息并返回
            m_errorCallback("error: handleNewConnection -> accept failed.");
            return;
        }
    }
    
    // ========== 成功接受一个新连接，开始处理 ==========
    
    // 获取客户端的 IP 地址和端口号
    char client_ip[INET6_ADDRSTRLEN] = {0}; // 足够容纳 IPv4 和 IPv6 地址
    unsigned short client_port = 0;
    
    // 根据地址族（IPv4 或 IPv6）提取客户端信息
    if (client_addr.ss_family == AF_INET) {
        // IPv4 地址
        auto addr4 = (struct sockaddr_in*)&client_addr;
        SocketIO::binToIpStr(AF_INET, &addr4->sin_addr, client_ip, sizeof(client_ip));
        client_port = ntohs(addr4->sin_port); // 网络字节序转主机字节序
    } else {
        // IPv6 地址
        auto addr6 = (struct sockaddr_in6*)&client_addr;
        SocketIO::binToIpStr(AF_INET6, &addr6->sin6_addr, client_ip, sizeof(client_ip));
        client_port = ntohs(addr6->sin6_port);
    }
    
    // 创建 TcpContext 对象，封装此连接的所有信息
    // 回调：RequestDisconnectCb，绑定到当前服务器的 handleClientDisconnect
    auto reqCb = [this](int fd) { this->handleClientDisconnect(fd); };
    auto context = std::make_shared<TcpContext>(client_fd, client_ip, client_port, reqCb);

    
    // 执行用户的连接回调。如果回调返回非 0，表示用户拒绝此连接
    if (m_clientConnectCallback(context) != 0) {
        // 用户拒绝了连接
        // context 对象会在离开作用域时自动销毁
        // TcpContext 的析构函数会自动关闭 client_fd
        return;
    }
    
    // 用户接受了连接，继续处理
    
    // 将新客户端 socket 设为非阻塞模式，以配合 epoll ET 模式
    SocketIO::setNonBlocking(client_fd);
    
    // 将新客户端 socket 加入 epoll，监听读事件和挂起事件
    // 使用 ET（边缘触发）模式以获得高性能
    // EPOLLET: 边缘触发模式
    // EPOLLIN: 读事件（有数据可读）
    // EPOLLRDHUP: 对端关闭连接或关闭写操作（半关闭）
    m_epollptr->addSocket(client_fd, EPOLLIN | EPOLLRDHUP | EPOLLET);
    
    // 将新客户端加入 map 进行管理。使用 fd 作为 key，TcpContext 的 shared_ptr 作为 value
    {
        std::lock_guard<std::mutex> lock(m_client_mutex);
        m_clientMap[client_fd] = context;
        ++m_current_client_count;
    }
    
    // 此处只处理一个连接就返回。如果还有等待的连接，由于监听 fd 使用 LT 模式，
    // epoll_wait 会在下次调用时再次返回 EPOLLIN 事件，eventLoop 会再次调用 handleNewConnection 来处理下一个连接。
}

/**
 * @brief 客户端数据处理的实现。
 * @param fd 发生数据到达事件的客户端文件描述符。
 */
inline void TcpServer::handleClientData(int fd)
{
    // 步骤 1: 获取客户端上下文
    std::shared_ptr<TcpContext> context;
    {
        std::lock_guard<std::mutex> lock(m_client_mutex);
        auto it = m_clientMap.find(fd);
        // 如果找不到对应的客户端，可能已经被清理，直接返回
        if (it == m_clientMap.end()) {
            return;
        }
        context = it->second;
    }

    // 步骤 2: 根据拆包规则进行不同的处理

    // ========== RAW 规则：无拆包，接收到数据就立即回调 ==========
    if (m_unpacking_rule == UnpackingRule::RAW) {
        // 循环读取直到缓冲区为空（ET 模式要求必须读到 EAGAIN）
        while (m_is_running) {
            // 使用 ioctl 查询内核缓冲区中的可读字节数。这样可以一次性读取所有数据，减少系统调用次数
            int bytes_available = 0;
            if (ioctl(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0) {
                // ioctl 成功，得知有 bytes_available 字节可读
                // 限制单次读取的最大大小为 64KB，防止恶意超大数据包占用过多内存
                size_t read_size = std::min(static_cast<size_t>(bytes_available), size_t(65536));
                
                // 动态分配合适大小的缓冲区
                std::vector<char> raw_buffer(read_size);
                
                ssize_t n = SocketIO::recvSocket(fd, raw_buffer.data(), raw_buffer.size());
                
                if (n > 0) {
                    // 成功收到数据，立即调用用户的数据回调
                    if (m_dataArrivedCallbackShared) {
                        // 使用共享指针版本回调
                        auto shared_buf = std::make_shared<std::vector<char>>(raw_buffer.begin(), raw_buffer.begin() + n);
                        m_dataArrivedCallbackShared(context, shared_buf);
                    } else {
                        // 使用原始指针版本回调
                        m_dataArrivedCallback(context, raw_buffer.data(), n);
                    }
                    

                } else if (n == 0) {
                    // recv 返回 0 表示对端正常关闭连接（FIN）
                    handleClientDisconnect(fd);
                    break; // 跳出循环
                } else {
                    // recv 返回 -1 表示出错
                    // EAGAIN 表示数据已读完，这是正常情况，跳出循环
                    if (errno == EAGAIN || errno == EWOULDBLOCK) { break; }

                    // 其他错误，认为连接异常，进行断开处理
                    handleClientDisconnect(fd);
                    break;
                }
            } else {
                // ioctl 失败或没有可读数据，回退到固定大小缓冲区策略
                char raw_buffer[8192]; // 8KB 固定缓冲区
                ssize_t n = SocketIO::recvSocket(fd, raw_buffer, sizeof(raw_buffer));
                
                if (n > 0) {
                    // 成功收到数据，立即调用用户的数据回调
                    m_dataArrivedCallback(context, raw_buffer, n);
                } else if (n == 0) {
                    // recv 返回 0 表示对端正常关闭连接
                    handleClientDisconnect(fd);
                    break;
                } else {
                    // recv 返回 -1 表示出错
                    if (errno == EAGAIN || errno == EWOULDBLOCK) { break; }
                    handleClientDisconnect(fd);
                    break;
                }
            }
        } // while 循环结束
        return; // RAW 模式处理完毕，直接返回
    }

    // ========== 其他规则（FIXED_LENGTH / LINE_BASED / HEADER_BODY）：需要应用层缓冲 ==========
    
    // 步骤 2.1: 先将所有数据从内核缓冲区读取到应用层缓冲区
    char temp_buffer[8192]; // 临时接收缓冲区，8KB
    
    while (m_is_running) {
        ssize_t n = SocketIO::recvSocket(fd, temp_buffer, sizeof(temp_buffer));
        
        if (n > 0) {
            // 成功收到数据，追加到上下文的私有接收缓冲区
            context->appendData(temp_buffer, n);
            
            // 追加数据后，立即检查缓冲区大小是否超过限制。防止内存被恶意占用
            // 只有在设置了限制（m_pack_length > 0）且非 FIXED_LENGTH 模式时才检查
            if (m_pack_length > 0 && m_unpacking_rule != UnpackingRule::FIXED_LENGTH) {
                // 对于 LINE_BASED 和 HEADER_BODY 模式，如果缓冲区累积数据超过限制，断开连接
                if (context->getRecvBufferSize() > m_pack_length) {
                    if (m_errorCallback) {
                        std::string mode_name;
                        if (m_unpacking_rule == UnpackingRule::LINE_BASED) {
                            mode_name = "LINE_BASED";
                        } else if (m_unpacking_rule == UnpackingRule::HEADER_BODY) {
                            mode_name = "HEADER_BODY";
                        }
                        
                        m_errorCallback("error: " + mode_name + " buffer size (" + 
                                      std::to_string(context->getRecvBufferSize()) + 
                                      ") exceeds limit (" + 
                                      std::to_string(m_pack_length) + 
                                      ") before complete packet, disconnecting client " +
                                      context->clientIp() + ":" + std::to_string(context->clientPort()));
                    }
                    // 断开连接并立即返回
                    handleClientDisconnect(fd);
                    return;
                }
            }
            
        } else if (n == 0) {
            // recv 返回 0 表示对端正常关闭连接
            handleClientDisconnect(fd);
            return; // 直接返回，不再处理缓冲区中的数据
        } else {
            // recv 返回 -1 表示出错
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // EAGAIN 表示数据已读完，跳出循环，继续处理缓冲区
                break;
            }
            // 其他错误，认为连接异常，进行断开处理
            handleClientDisconnect(fd);
            return;
        }
    }

    // 步骤 2.2: 在应用层缓冲区中循环解析完整的数据包。循环直到无法再提取完整包为止
    while (m_is_running) {
        bool did_process_packet = false; // 标志：本轮循环是否成功处理了一个包
        
        // 根据拆包规则进行不同的处理
        switch (m_unpacking_rule) {
            case UnpackingRule::HEADER_BODY: {
                // 【头部+消息体】格式：前 4 字节表示消息体长度，后面是消息体
                
                // 检查是否至少有 4 字节头部
                if (context->getRecvBufferSize() < 4) {
                    break; // 数据不足，等待更多数据
                }
                
                // 读取前 4 字节，解析出消息体长度
                uint32_t body_len;
                memcpy(&body_len, context->getRecvBuffer().data(), sizeof(body_len));
                
                // 【关键】检查消息体长度是否超过限制（如果设置了限制）
                if (m_pack_length > 0 && body_len > m_pack_length) {
                    if (m_errorCallback) {
                        m_errorCallback("error: HEADER_BODY message body length (" + 
                                      std::to_string(body_len) + 
                                      ") exceeds limit (" + 
                                      std::to_string(m_pack_length) + 
                                      "), disconnecting client " +
                                      context->clientIp() + ":" + std::to_string(context->clientPort()));
                    }
                    // 消息体长度超限，断开连接
                    handleClientDisconnect(fd);
                    return; // 直接返回，不再处理
                }
                
                // 计算完整包的总长度：4 字节头部 + 消息体长度
                size_t total_len = 4 + body_len;
                
                // 检查缓冲区中的数据是否足够构成完整的包
                if (context->getRecvBufferSize() < total_len) {
                    break; // 数据不足，等待更多数据
                }
                
                // 数据足够，调用用户的数据到达回调（传递完整的包，包括 4 字节头部）
                if (m_dataArrivedCallbackShared) {
                    // 使用共享指针版本回调
                    auto shared_buf = std::make_shared<std::vector<char>>(
                        context->getRecvBuffer().begin(), 
                        context->getRecvBuffer().begin() + total_len
                    );
                    m_dataArrivedCallbackShared(context, shared_buf);
                } else {
                    // 使用原始指针版本回调
                    m_dataArrivedCallback(context, context->getRecvBuffer().data(), total_len);
                }

                // 从缓冲区中移除已处理的包
                context->getRecvBuffer().erase(context->getRecvBuffer().begin(), 
                                              context->getRecvBuffer().begin() + total_len);
                
                // 标记本轮成功处理了一个包
                did_process_packet = true;
                break;
            }
            
            case UnpackingRule::LINE_BASED: {
                // 【行拆包】格式：以 "\r\n" 作为消息边界
                
                auto& buffer = context->getRecvBuffer();
                
                // 在缓冲区中查找 "\r\n"
                auto it = std::search(buffer.begin(), buffer.end(), "\r\n", "\r\n" + 2);
                
                // 如果找不到 "\r\n"，说明还没有完整的一行
                if (it == buffer.end()) {
                    // 【关键】虽然在读取阶段已经检查过，但这里再次检查以确保安全。如果设置了限制且缓冲区大小超限，断开连接
                    if (m_pack_length > 0 && buffer.size() > m_pack_length) {
                        if (m_errorCallback) {
                            m_errorCallback("error: LINE_BASED line length (" + 
                                          std::to_string(buffer.size()) + 
                                          ") exceeds limit (" + 
                                          std::to_string(m_pack_length) + 
                                          ") without finding \\r\\n, disconnecting client " +
                                          context->clientIp() + ":" + std::to_string(context->clientPort()));
                        }
                        handleClientDisconnect(fd);
                        return;
                    }
                    break; // 等待更多数据
                }
                
                // 找到了 "\r\n"，计算包括 "\r\n" 在内的总长度
                size_t line_len = std::distance(buffer.begin(), it) + 2;
                
                // 【关键】检查单行长度是否超过限制（如果设置了限制）
                if (m_pack_length > 0 && line_len > m_pack_length) {
                    if (m_errorCallback) {
                        m_errorCallback("error: LINE_BASED line length (" + 
                                      std::to_string(line_len) + 
                                      ") exceeds limit (" + 
                                      std::to_string(m_pack_length) + 
                                      "), disconnecting client " +
                                      context->clientIp() + ":" + std::to_string(context->clientPort()));
                    }
                    // 单行长度超限，断开连接
                    handleClientDisconnect(fd);
                    return; // 直接返回，不再处理
                }
                
                // 长度合法，调用用户的数据到达回调（传递完整的一行，包括 "\r\n"）
                if (m_dataArrivedCallbackShared) {
                    // 使用共享指针版本回调
                    auto shared_buf = std::make_shared<std::vector<char>>(
                        buffer.begin(), 
                        buffer.begin() + line_len
                    );
                    m_dataArrivedCallbackShared(context, shared_buf);
                } else {
                    // 使用原始指针版本回调
                    m_dataArrivedCallback(context, buffer.data(), line_len);
                }
                
                
                // 从缓冲区中移除已处理的行
                buffer.erase(buffer.begin(), buffer.begin() + line_len);
                
                // 标记本轮成功处理了一个包
                did_process_packet = true;
                break;
            }
            
            case UnpackingRule::FIXED_LENGTH: {
                // 【固定长度拆包】：每个包的长度固定
                
                // 检查配置：固定长度不能为 0
                if (m_pack_length == 0) {
                    if(m_errorCallback) {
                        m_errorCallback("error: FIXED_LENGTH unpacking rule requires pack_length > 0, but pack_length is 0.");
                    }
                    // 配置错误，断开连接
                    handleClientDisconnect(fd);
                    return;
                }
                
                // 检查缓冲区中的数据是否足够构成一个完整的包
                if (context->getRecvBufferSize() < m_pack_length) {
                    break; // 数据不足，等待更多数据
                }
                
                // 数据足够，调用用户的数据到达回调（传递固定长度的消息）
                if (m_dataArrivedCallbackShared) {
                    // 使用共享指针版本回调
                    auto shared_buf = std::make_shared<std::vector<char>>(
                        context->getRecvBuffer().begin(), 
                        context->getRecvBuffer().begin() + m_pack_length
                    );
                    m_dataArrivedCallbackShared(context, shared_buf);
                } else {
                    // 使用原始指针版本回调
                    m_dataArrivedCallback(context, context->getRecvBuffer().data(), m_pack_length);
                }

    
                // 从缓冲区中移除已处理的消息
                context->getRecvBuffer().erase(context->getRecvBuffer().begin(), 
                                              context->getRecvBuffer().begin() + m_pack_length);
                
                // 标记本轮成功处理了一个包
                did_process_packet = true;
                break;
            }
            
            case UnpackingRule::RAW:
                // RAW 模式在前面已经处理过，这里不会执行到
                // 这个 case 只是为了防止编译器警告（switch 没有覆盖所有枚举值）
                break;
        } // switch 结束
        
        // 如果本轮循环没有成功处理任何包，说明缓冲区中的数据不足以构成完整的包
        // 跳出循环，等待下次有数据到达时再继续处理
        if (!did_process_packet) {
            break;
        }
        
        // 如果成功处理了一个包，继续循环，尝试从缓冲区中提取下一个包
        // 这样可以一次性处理缓冲区中的所有完整包
    } // while 循环结束
}

/**
 * @brief 客户端断开处理的实现。
 * @param fd 断开连接的客户端文件描述符。
 * @details 这是清理客户端资源的唯一统一入口，确保所有断开场景都经过相同的清理流程。
 */
inline void TcpServer::handleClientDisconnect(int fd)
{
    // 步骤 1: 从客户端管理 map 中获取并移除该连接
    std::shared_ptr<TcpContext> context;
    {
        // 加锁以安全地访问和修改 m_clientMap
        std::lock_guard<std::mutex> lock(m_client_mutex);
        
        // 查找该 fd 对应的客户端
        auto it = m_clientMap.find(fd);
        
        // 如果找不到，说明该连接已经被清理过了。这可能发生在多个事件（如 EPOLLIN 和 EPOLLHUP）同时触发的情况下。防止重复处理同一个断开连接
        if (it == m_clientMap.end()) { return; }
        
        // 获取 TcpContext 的 shared_ptr，并保存在局部变量中
        // 这样即使从 map 中移除，对象也不会立即销毁
        context = it->second;
        
        // 从 map 中移除该连接。此时 map 中对 TcpContext 的引用被移除，引用计数减 1
        m_clientMap.erase(it);
        if (m_current_client_count > 0) --m_current_client_count;
    } // 锁在此处释放

    // 步骤 2: 从 epoll 监听中移除该 fd。这样 epoll_wait 就不会再返回此 fd 的事件
    m_epollptr->deleteSocket(fd);

    // 关闭 fd ，忽略 close 的返回值（可记录错误），避免抛出或阻塞
    SocketIO::closeSocket(fd);

    // 标记 context 内部状态（由 TcpServer 管理）
    if (context) {
        context->m_fd = -1;            // friend 允许直接写
        context->m_ConnectedStatus = false;
    }
    
    // 步骤 3: 调用用户的断开连接回调。如果用户还想访问 context，这个 shared_ptr 保证对象在回调期间存活
    // 用户可以在此回调中进行清理工作、日志记录、统计信息更新等
    m_clientDisconnectCallback(context);

    // 步骤 4: 资源自动清理
    // 当此函数返回时，局部变量 context 被销毁。
    // 如果这是最后一个指向 TcpContext 对象的 shared_ptr（通常情况下是），则 TcpContext 对象会被自动析构。
    // TcpContext 的析构函数会自动关闭 socket fd，完成最终的资源释放。

}

} // namespace xdg

#endif // _XDG_TCP_SERVER_HPP_